﻿using System.Reflection;

namespace DoSomethings;

public class ReflectionImplDI
{
    private static Assembly assembly = Assembly.GetCallingAssembly();
    private static Type[] types;
    static ReflectionImplDI()
    {
        // 获取当前程序集并获取元数据信息
        types = assembly.GetTypes();
    }

    /// <summary>
    /// 判断控制器 Controller 是否存在
    /// </summary>    
    private static (bool, Type?) IsHasController(string controllerName)
    {
        // 不分大小写
        string name = controllerName + "Controller";
        var type = types.FirstOrDefault(u => u.Name.ToLower() == name.ToLower());
        return (type != null, type);
    }

    /// <summary>
    /// 判断 Action 是否存在
    /// </summary>    
    private static bool IsHasAction(Type type, string actionName)
    {
        return type.GetMethods().Any(u => u.Name.ToLower() == actionName.ToLower());
    }

    public static object[] CreateType(Type type)
    {
        // 只使用一个构造函数，可能有多个构造函数，但是netcore中 controller一般只有一个构造函数
        ConstructorInfo? contruct = type.GetConstructors().FirstOrDefault();

        // 通常参数类型有三种可能  接口类型  抽象类型  正常的class类型
        // 获取类型的构造函数参数
        ParameterInfo[] paramList = contruct.GetParameters();

        // 依赖注入对象列表
        List<object> objList = new List<object>();

        foreach (ParameterInfo item in paramList)
        {
            // 找到继承该接口参数的类型 这里只考虑了参数类型为接口的情况
            Type who = types.FirstOrDefault(u => u.GetInterfaces().Any(x => x.Name == item.ParameterType.Name));

            // 实例化
            object create = Activator.CreateInstance(who, new object[] { });
            objList.Add(create);
        }
        return objList.ToArray();
    }

    private static object StartASPNETCORE(Type type, string actionName, params object[] actionParamList)
    {
        // 方法名一样，参数个数也一样
        MethodInfo method = type.GetMethods().FirstOrDefault(u => u.Name.ToLower() == actionName.ToLower() && u.GetParameters().Length == actionParamList.Length);

        if (method == null) return null;

        #region 实例化控制器
        // 获取controller依赖的对象
        object[] inject = CreateType(type);
        // 注入依赖，实例化controller对象
        object controller = Activator.CreateInstance(type, inject);
        #endregion
        object result;
        try
        {
            // 调用action
            result = method.Invoke(controller, actionParamList);
            return result;
        }
        catch
        {
            result = "500";
            return result;
        }
    }

    public static void Run()
    {
        while (true)
        {
            string read = string.Empty;
            Console.WriteLine("输入控制器名称：");
            read = Console.ReadLine();
            // 检查是否有该控制器并获取type
            var hasController = IsHasController(read);
            if (!hasController.Item1)
            {
                Console.WriteLine("404");
                continue;
            }

            Console.WriteLine("请输入要访问的action：");
            read = Console.ReadLine();
            if (!IsHasAction(hasController.Item2, read))
            {
                Console.WriteLine("404");
                continue;
            }

            Console.WriteLine("URL 存在,输入参数(空格隔开)：");
            var paramList = Console.ReadLine().Split(' ');
            object res = StartASPNETCORE(hasController.Item2, read, paramList);
            Console.WriteLine($"执行结果是{res}");
            Console.ReadKey();
        }
    }
}

public interface ITest
{
    string Add(string a, string b);
}

public class Test : ITest
{
    public string Add(string a, string b)
    {
        Console.WriteLine("Add方法执行");
        return a + b;
    }
}
public class TestController
{
    private readonly ITest _test;

    public TestController(ITest test)
    {
        _test = test;
    }

    public string Action(string a, string b)
    {
        Console.WriteLine("开始添加");
        var res = _test.Add(a, b);
        Console.WriteLine("添加完成");
        return res;
    }
}